package org.ricks.classfile;

import java.lang.classfile.*;
import java.lang.constant.ClassDesc;
import java.lang.constant.MethodTypeDesc;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class DynamicProxyGenerator {
    public static Class<?> generateProxyClass(Class<?> targetClass) throws Exception {
        ClassDesc proxyClassDesc = ClassDesc.of("com.example.Proxy"); // 代理类名称

        // 使用 Class-File API 构建类
        byte[] bytecode = ClassFile.of().build(proxyClassDesc, classBuilder -> {
            classBuilder.withSuperclass(ClassDesc.of("java.lang.Object")); // 继承 Object

            // 添加目标类的方法代理
            for (var method : targetClass.getDeclaredMethods()) {
                classBuilder.withMethod(
                        method.getName(),
                        MethodTypeDesc.of(ClassDesc.of(method.getReturnType().getName())),
                        ClassFile.ACC_PUBLIC,
                        methodBuilder -> generateProxyMethod(methodBuilder, method)
                );
            }
        });

        // 通过 Lookup 动态加载类
        return MethodHandles.lookup().defineClass(bytecode);
    }

    private static void generateProxyMethod(MethodBuilder methodBuilder, Method targetMethod) {
        methodBuilder.withCode(codeBuilder -> {
            // 方法体逻辑：调用 InvocationHandler
            codeBuilder
                    .aload(0)                                   // 加载 this
                    .getfield(ClassDesc.of("com.example.Proxy"), "handler", ClassDesc.of(InvocationHandler.class.getName()))
                    .aload(0)                                   // 加载代理实例

//                    .constantMethod(targetMethod)               // 目标方法常量
                    .aload(1)                                   // 加载参数数组
                    .invokevirtual(ClassDesc.of(InvocationHandler.class.getName()), "invoke",
                            MethodTypeDesc.of(ClassDesc.of(Object.class.getName()),
                                    ClassDesc.of(Object.class.getName())))
                    .areturn();                                  // 返回结果
        });
    }
}
